/**
 *实现call 方法
 */
Function.prototype.myCall = function (context, ...args) {
    context = context || this
    // 将原来的函数存一下
    let oldFn = context;
    // 将被调用函数赋值给原来函数的p属性
    oldFn.p = this
    // 调用函数
    oldFn.p(...args)
    delete oldFn.p
}

/**
 * 实现apply方法
 * @param {*} context 
 * @param {*} args 
 */
Function.prototype.myApply = function (context, ...args) {
    context = context || this
    // 将原来的函数存一下
    let oldFn = context;
    // 将被调用函数赋值给原来函数的p属性
    oldFn.p = this
    // 调用函数
    oldFn.p(...args)
    delete oldFn.p
}

/**
 * 实现bind方法
 * @param {*} context 
 */
Function.prototype.myBind = function (context) {
    let oldFn = this; // 将要改变this指向的函数存起来
    let args = [...arguments].slice(1) // 拿到除了this目标之外的参数
    // 声明一个拷贝的目标函数
    let fn = function () {
        //拿到bind后的函数调用传递参数,并用于拼接在返回的函数后面
        let argum = [...arguments]
        // 若要变改变this指向的函数是构造函数,则将this指向指向实例对象(bind不能改变构造函数this指向)
        if (this instanceof fn) {
            oldFn.apply(this, args.concat(argum))
        } else {
            oldFn.apply(context, args.concat(argum))
        }
    }
    return fn
}


let obj = {
    name: '刘德华',
    say(a, b, c, d) {
        console.log(this.name + a + b + c + d);
    }
}

let obj1 = {
    name: "周杰伦"
}
let obj2 = {
    name: '张学友'
}




// ES5继承
function Father(name, age) {
    this.name = name;
    this.age = age;
}
function Son() { }
// 继承: 让子构造函数原型对象等于父构造函数的实例;再将子构造函数的consturctor指回子子构造函数
let father = new Father('刘德华', 18)

Son.prototype = father;
Son.prototype.consturctor = Son;

let son = new Son()
console.log(son.name); // 刘德华
console.log(son.age); // 18


// call继承、
function Father1(name, age) {
    this.name = name;
    this.age = age;
}
function Son1(name, age) {
    Father1.call(this, name, age)
}
let son1 = new Son1('刘德华', 29)
console.log(son1.name); // 刘德华
console.log(son1.age); // 18

// class 继承
class Father2 {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}
class Son2 extends Father2 {
    constructor(name, age) {
        super(name, age)
    }
}

let son2 = new Son2("张三", 20)
console.log(son2.name); // 张三
console.log(son2.age); // 20


function deepClone(source) {
    if (!source || typeof source !== 'object') {
        return source
    }
    let targetObj = Array.isArray(source) ? [] : {}
    Object.keys(source).forEach(key => {
        if (source[key] && typeof source[key] === 'object') {
            targetObj[key] = deepClone(source[key])
        } else {
            targetObj[key] = source[key]
        }
    })
    return targetObj
}


let obj3 = "234"

let cloneObj = deepClone(obj3)

console.log(cloneObj);